#include "Map.hpp"
#include <cmath>
#include <fstream>
using namespace std;

Map::~Map()
{
	for(list<Portal*>::iterator it = m_portals.begin(); it != m_portals.end(); it++)
	{
		delete (*it);
	}
}

void Map::bruteLoad(string pathToMapping, string pathToTileset, string pathToCollisionMask, 
		unsigned int width, unsigned int height)
{
	//first clean
	for(list<Portal*>::iterator it = m_portals.begin(); it != m_portals.end(); it++)
	{
		delete (*it);
	}
	m_portals.clear();
	m_mapping.clear();

	//load the things
	m_tileset.load(pathToTileset);
	m_tileset.loadCollisionMask(pathToCollisionMask);
	m_width = width;
	m_height = height;
	ifstream file;
	file.open(pathToMapping);
	if(file.is_open())
	{
		while(file.good())
		{
			unsigned int data;
			file>>data;
			if(!file.fail())
				m_mapping.push_back(data);
			else
				throw string("Error while loadng the map data.");
		}
	}
	else
		throw string("Unable to load the map data.");
	if(m_mapping.size() != width*height)
		throw string("Bad size of map data.");
}

void Map::checkEntityPosition(Entity& ent)
{
	for(unsigned int x=0; x<m_width;x++)
		for(unsigned int y =0; y<m_height; y++)
		{
			Hitbox hit(x*32.f,y*32.f,32.f,32.f);
			if(m_tileset.checkColliding(m_mapping[x + y*m_width]) && ent.getHitbox().collide(hit))
			{
				//move the entity,but first choose the best axe to move
				float deltaX = abs(abs(ent.centralX() - hit.centerX()) - (hit.width()+ent.getHitbox().width())/2.f); //the distance between their borders on X axe
				float deltaY = abs(abs(ent.centralY() - hit.centerY()) - (hit.height()+ent.getHitbox().height())/2.f);
				if(deltaX < deltaY) //the smallest move is on X axe
				{
					if(ent.x() < hit.x())
						ent.setPosition(ent.x()-deltaX,ent.y());
					else
						ent.setPosition(ent.x()+deltaX,ent.y());
				}
				else
				{
					if(ent.y() < hit.y())
						ent.setPosition(ent.x(),ent.y()-deltaY);
					else
						ent.setPosition(ent.x(),ent.y()+deltaY);
				}
			}
		}
}

float Map::width() const
{
	return m_width * 32.f;
}

float Map::height() const
{
	return m_height * 32.f;
}

void Map::loadMap1()
{
	bruteLoad("res/map/map1.txt", "res/img/tileset/tileset.png", "res/img/tileset/collisionMask.txt",10,7);
	m_portals.push_back(new Portal(9.f*32.f + 16.f,3*32.f,16.f,32.f,2,33.f,64.f));
}

void Map::loadMap2()
{
	bruteLoad("res/map/map2.txt", "res/img/tileset/tileset.png", "res/img/tileset/collisionMask.txt",10,37);
	m_portals.push_back(new Portal(0,2*32.f,16.f,32.f,1,8*32.f-1.f,3*32.f));
	m_portals.push_back(new Portal(9*32.f+16.f,33*32.f,16.f,32.f,3,33.f,19*32.f));
}

void Map::loadMap3()
{
	bruteLoad("res/map/map3.txt", "res/img/tileset/tileset.png", "res/img/tileset/collisionMask.txt",26,23);
	m_portals.push_back(new Portal(0,19*32.f+16.f,16.f,32.f,2,8*32.f-1.f,33*32.f));
}

bool Map::changeMap(Entity* entity, unsigned int& nextMap, sf::Vector2f& destination)
{
	for(list<Portal*>::iterator it = m_portals.begin(); it != m_portals.end(); it++)
	{
		if(entity->getHitbox().collide((*it)->m_hitbox))
		{
			nextMap = (*it)->m_nextMap;
			destination = (*it)->m_destination;
			return true;
		}
	}
	return false;
}

void Map::draw(sf::RenderWindow& window)
{
	for(unsigned int x = 0; x < m_width; x++)
		for(unsigned int y = 0; y < m_height; y++)
		{
			//m_mapping[m_width * y + x];
			sf::Sprite sprite;
			m_tileset.setSprite(sprite, m_mapping[m_width * y + x]);
			sprite.setPosition(x*32.f, y*32.f);
			sprite.setScale(2.,2.);
			window.draw(sprite);
		}
}
